﻿using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Windows;

namespace Aliphant.Mvvm.XEvent.Mvvm
{
    public static class ViewModelProvider
    {
        private static string viewPath = ".Views.";

        public static string? GetLocationPath(DependencyObject obj)
        {
            return (string?)obj.GetValue(LocationPathProperty);
        }

        public static void SetLocationPath(DependencyObject obj, string? value)
        {
            obj.SetValue(LocationPathProperty, value);
        }

        public static readonly DependencyProperty LocationPathProperty =
            DependencyProperty.RegisterAttached("LocationPath", typeof(string), typeof(ViewModelProvider), new PropertyMetadata(null, LocationPathChanged));

        private static void LocationPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!DesignerProperties.GetIsInDesignMode(d))
            {
                string? path = (string?)e.NewValue;
                if (!string.IsNullOrEmpty(path))
                {
                    viewPath = "." + path + ".";
                }
            }
        }

        public static DependencyProperty AutoWireViewModelProperty =
            DependencyProperty.RegisterAttached("AutoWireViewModel", typeof(bool?), typeof(ViewModelProvider), new PropertyMetadata(null, AutoWireViewModelChanged));

        /// <summary>
        /// 自动绑定ViewModel
        /// </summary>
        /// <param name="d">依赖的对象</param>
        /// <param name="e">自动绑定事件</param>
        private static void AutoWireViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!DesignerProperties.GetIsInDesignMode(d))
            {
                bool? flag = (bool?)e.NewValue;
                if (flag.HasValue && flag.Value)
                {
                    AutoWireViewModelChange(d, Bind);
                }
            }
        }

        public static bool? GetAutoWireViewModel(DependencyObject obj)
        {
            return (bool?)obj.GetValue(AutoWireViewModelProperty);
        }

        public static void SetAutoWireViewModel(DependencyObject obj, bool? value)
        {
            obj.SetValue(AutoWireViewModelProperty, value);
        }

        public static void AutoWireViewModelChange(object view, Action<object, object> setDataContextCallback)
        {
            Type vmType = GetViewModelType(view.GetType());
            if (vmType != null)
            {
                object obj = GetViewModelObject(view, vmType);
                if (obj != null)
                {
                    setDataContextCallback(view, obj);
                }
            }
        }

        public static Type? GetViewModelType(Type viewType)
        {
            string fullName = viewType.FullName ?? string.Empty;
            if (!string.IsNullOrEmpty(fullName))
            {
                fullName = fullName.Replace(viewPath, ".ViewModels.");
                string fullName2 = viewType.GetTypeInfo().Assembly.FullName ?? string.Empty;
                if (!string.IsNullOrEmpty(fullName2))
                {
                    string arg = (fullName.EndsWith("View") ? "Model" : "ViewModel");
                    string fmt = string.Format(CultureInfo.InvariantCulture, "{0}{1}, {2}", fullName, arg, fullName2);
                    return Type.GetType(fmt);
                }
            }
            return null;
        }

        public static object GetViewModelObject(object view, Type vmType)
        {
            return view.GetType().Assembly.CreateInstance(vmType.ToString());
        }

        public static void Bind(object view, object viewModel)
        {
            FrameworkElement frameworkElement = view as FrameworkElement;
            if (frameworkElement != null)
            {
                frameworkElement.DataContext = viewModel;
            }
        }
    }
}
